_FBME = function() {
  _FBMSettings.setValue("marketing_text_comments", _FBMSettings.getValue("marketing_text_wall"));
}

jqFbm.extend(_FBME.prototype, _MECore.prototype, {
  FB_DEFAULT_STATUS_MSG: "What's on your mind?",
  platform: "facebook",

  insertSmileyInString: function(str, smiley, position) {
    str = str.substr(0, position) + smiley + " " + str.substr(position);
    return str;
  },

  FFLegacyInsertSmiley: function(ev) {
    //ev.stopPropagation();
    var el = jqFbm(ev.target),
      scope = this.getElData(el.parents("._fbm-emoticons-wrapper").first(), "scope"),
      context = this.getElData(el.parents("._fbm-emoticons-wrapper").first(), "context"),
      t = this.activeInput;

    if(!t.hasClass("_fbm-input_used")) { //first time smiley
      t.addClass("_fbm-input_used");
      this.resetCounter(scope);
      this.promoUsed = false;
    }

    var freq = _FBMSettings.getValue("marketing_text_frequency") ? _FBMSettings.getValue("marketing_text_frequency") : 1;
    if(this.getMsgCount(scope) % freq == 0 && !this.promoUsed) {
      this.insertPromo = true;
    }

    var promo = null;
    var emoId = this.extractEmoticonDisplayId(el);
    var realId = this.getElData(el, "emoid");

    if(this.insertPromo && !this.promoUsed) {
      promo = this.getEmoticonCode(emoId, scope, true);
      this.promoUsed = true;
      this.sanityCheck = true;
    } else {
      promo = this.getEmoticonCode(emoId, scope, false);
      this.sanityCheck = false;
    }

    var code = promo.code;
    var promoTxt = promo.mktTxt;

    if(scope == this.SCOPE_CHAT) {
      //apply emoticon to chat textarea
      t.get(0).focus();
      t.val(t.val() + code + " ");
      this.txtBuff = t.val(); //used for marketing text

      if(!this.chat_txtarea) {
        this.chat_txtarea = t;
      }
      this.sendStats({event: "insertSmiley",
        gid: el.closest("._fbm-galcontent").attr("id"),
        icon: realId,
        mktTxt: promoTxt,
        context: "CHAT"});

    } else if(scope == this.SCOPE_WALL) {
      //apply emoticon to status textarea
      t.get(0).focus();

      setTimeout(jqFbm.proxy(function() {
        if(t.val() == this.FB_DEFAULT_STATUS_MSG)
          t.val(code);
        else
          t.val(t.val() + code + " ");
        t.closest("div.uiTypeahead").next("input[type='hidden'].mentionsHidden").val(t.val());

        var statsContext = context == "messages" || context == "messages_reply" ? "MESSAGES" : "WALL";
        this.sendStats({event: "insertSmiley",
          gid: el.closest("._fbm-galcontent").attr("id"),
          icon: realId,
          mktTxt: promoTxt,
          context: statsContext});
      }, this), 100);
    }

    this.insertPromo = false;
    this.hideSmileysPanel();
  },

  insertSmiley: function(ev) {
    //ev.stopPropagation();
    var el = jqFbm(ev.target),
      scope = this.getElData(el.parents("._fbm-emoticons-wrapper").first(), "scope"),
      context = this.getElData(el.parents("._fbm-emoticons-wrapper").first(), "context"),
      t = this.activeInput;

    //var promo = null;
    var emoId = this.extractEmoticonDisplayId(el);
    var realId = this.getElData(el, "emoid");

    promo = this.getEmoticonCode(emoId, scope, false);

    var code = promo.code;
    var promoTxt = promo.mktTxt;
    var emoticonMatch = code.match(/\(([^\\)~]*)#\)/i);

    this.setElData(t, "_fbm-scope", scope); //add scope to input element (useful later to apply mkt message)
    if(scope == this.SCOPE_CHAT) {
      //apply emoticon to chat textarea
      t.get(0).focus();

      //insert smiley & correct caret position
      var caretPos = t.get(0).selectionStart;
      t.val(this.insertSmileyInString(t.val(), code, caretPos));
      if(emoticonMatch && emoticonMatch.length) {
        caretPos += emoticonMatch[0].length + 1;
      }
      t.caret(caretPos);

      if(!this.chat_txtarea) {
        this.chat_txtarea = t;
      }

      this.sendStats({event: "insertSmiley",
        gid: el.closest("._fbm-galcontent").attr("id"),
        icon: realId,
        mktTxt: promoTxt,
        context: "CHAT"});

      //adjust textarea height
      t.trigger("autosize");
      //adjust chat panel height
      this.adjustChatPanelSize(t.closest(".fbDockChatTabFlyout"));
    } else if(scope == this.SCOPE_WALL) {
      //apply emoticon to status textarea
      t.get(0).focus();

      //correct caret position
      var caretPos = t.get(0).selectionStart;


      setTimeout(jqFbm.proxy(function() {
        //insert smiley & correct caret position
        t.val(this.insertSmileyInString(t.val(), code, caretPos));
        if(emoticonMatch && emoticonMatch.length) {
          caretPos += emoticonMatch[0].length + 1;
        }
        t.caret(caretPos);
        t.trigger("autosize");
        t.closest("div.uiTypeahead").next("input[type='hidden'].mentionsHidden").val(t.val());
        var statsContext = context == "messages" || context == "messages_reply" ? "MESSAGES" : "WALL";
        this.sendStats({event: "insertSmiley",
          gid: el.closest("._fbm-galcontent").attr("id"),
          icon: realId,
          mktTxt: promoTxt,
          context: statsContext});
      }, this), 100);
    }

    this.hideSmileysPanel();
  },

  adjustChatPanelSize: function(panel) {
    if(!panel.length) return;
    var inner = panel.find(".fbNubFlyoutInner");
    var body = inner.find(".fbNubFlyoutBody");
    var diff = panel.height() - inner.height();
    if(diff) {
      body.height(body.height() + diff);
      body.scrollTop(99999);
    }
  },

  onGIconClick: function(e) {
    var t = (new Date()).getTime() - this.openedAt;
    if(t < 300) return;

    var target = jqFbm(e.target);
    this.onWallTextareaFocus(target);
    this.onStatusTextareaFocus(target);
    this.onPhotoCommentsFocus(target);

    /*
     handle icon click events
     1. click on icon non-comment context
     2. click on icon comment context
     3. focus on icon comment context
     4. 2 & 3 almost simultaneously
     */
    if(target.is("span._fbm-down-arrow")) {
      target = target.closest("a._fbm-button");
    }

    if(target.is("a._fbm-button")) {
      var statsContext,
        context = this.getElData(target.closest("._fbm-bar"), "context"),
        smPanelOptions = {
          galleryId: target.attr("galleryid"),
          topCt: this.smileysPanelCt,
          context: context
        };

      e.stopPropagation();
      e.preventDefault();
      if(context == "chat" && e.type == "click") {
        //context chat
        statsContext = "CHAT";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest(".fbNubFlyoutInner").find("textarea").first(),
          scope: this.SCOPE_CHAT,
          where: "left",
          alignTo: target.closest("._fbm-bar"),
          scrollType: "fixed"
        });
        this.showHideSmileysPanel(smPanelOptions);
      } else if(jqFbm.inArray(context, ["status", "photo_share", "photo_comments"]) > -1 && e.type == "click") {
        //context status
        statsContext = "WALL";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest("._fbm-bar").parent().find('textarea.mentionsTextarea').first(),
          scope: this.SCOPE_WALL,
          where: "under",
          alignTo: jqFbm(e.target),
          scrollType: context == "photo_share" ? "fixed" : "absolute"
        });
        this.showHideSmileysPanel(smPanelOptions);
      } else if(context == "comments") {
        statsContext = "WALL";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest(".uiMentionsInput").find('textarea.mentionsTextarea').first(),
          scope: this.SCOPE_WALL,
          where: "under",
          alignTo: jqFbm(e.target),
          scrollType: "absolute"
        });
        this.showHideSmileysPanel(smPanelOptions);
      } else if (context == "messages" && e.type == "click") {
        //context "send message"
        statsContext = "MESSAGES";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest("div._20z").find('textarea').first(),
          scope: this.SCOPE_WALL,
          where: "under",
          alignTo: jqFbm(e.target),
          scrollType: "fixed"
        });
        this.showHideSmileysPanel(smPanelOptions);
      } else if (context == "messages_reply" && e.type == "click") {
        statsContext = "MESSAGES";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest("div.MessagingComposerForm").find('textarea.MessagingComposerBody').first(),
          scope: this.SCOPE_WALL,
          where: "under",
          alignTo: jqFbm(e.target),
          scrollType: "absolute"
        });
        this.showHideSmileysPanel(smPanelOptions);
      } else if (context == "messages_reply_new" && e.type == "click") {
        statsContext = "MESSAGES";
        jqFbm.extend(smPanelOptions, {
          targetInput: target.closest("div._2pt").find('textarea').first(),
          scope: this.SCOPE_WALL,
          where: "under",
          alignTo: jqFbm(e.target),
          scrollType: "absolute"
        });
        this.showHideSmileysPanel(smPanelOptions);
      }

      if(statsContext) {
        this.sendStats({
          event: "openGallery",
          gid: target.attr("galleryid"),
          context: statsContext
        });
      }
    } else if(target.is("a.close-btn") || !(target.closest("._fbm-bar").length || target.closest("._fbm-emoticons-wrapper").length || (target.hasClass("UIImageBlock") && target.hasClass("mentionsAddComment")))){
      this.hideSmileysPanel();
    }
  },

  FFLegacyAddChatBoxIcons: function() {
    var ct = jqFbm(".fbDockChatTabFlyout .fbNubFlyoutOuter .fbNubFlyoutInner");
    if(!ct.length) { delete ct; return; }
    if(this.galleries === null) return;
    var _this = this;
    ct.each(function() {
      if(!jqFbm(this).find("._fbm-bar").length) {
        var tpl = _this.generateGalleryBarHtml("chat", true);
        jqFbm(this).find(".fbNubFlyoutFooter").before(tpl);
        var txtArea = jqFbm(this).find("textarea");

        _this.txtBuff = "";
        txtArea.keydown(function(e) {
          if(e.keyCode == 13) {
            //count smileys
            _this.countSmileys(_this.txtBuff, _this.SCOPE_CHAT);
            _this.promoUsed = false;
            _this.txtBuff = "";
            return;
          }
          _this.txtBuff = jqFbm(e.currentTarget).val();
        });
        //readjust chat window size
        var diff = jqFbm(this).find(".fbNubFlyoutBody").height() - jqFbm(this).find("._fbm-bar").height() - 3;
        jqFbm(this).find(".fbNubFlyoutBody").css({height: diff + "px"});
      };
    });

    delete ct;
  },

  addChatBoxIcons: function() {
    var ct = jqFbm(".fbDockChatTabFlyout .fbNubFlyoutOuter .fbNubFlyoutInner");
    if(!ct.length) { delete ct; return; }
    if(this.galleries === null) return;
    var _this = this;
    ct.each(function() {
      if(!jqFbm(this).find("._fbm-bar").length) {
        var tpl = _this.generateGalleryBarHtml("chat", true);
        jqFbm(this).find(".fbNubFlyoutFooter").before(tpl);
        var txtArea = jqFbm(this).find("textarea");
        txtArea.autosize();
        _this.setElData(txtArea, "_fbm-original-height", txtArea.height());

        //readjust chat window size
        _this.adjustChatPanelSize(jqFbm(this).closest(".fbDockChatTabFlyout"));
      };
    });
    delete ct;
  },

  addStatusBoxIcons: function(ct) {
    var _this = this;
    if(ct.length && !ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(_this.galleries)) {
      ct.append(_this.generateGalleryBarHtml("status"));
    }
  },

  addWallCommentsIcons: function(ct) {
    if(ct.length && !ct.find("._fbm-bar").length) {
      ct.append(this.generateGalleryBarHtml("comments"));
    }
  },

  addNewMessageIcons: function() {
    var ct = jqFbm("div._1yv ._1yu ._20z"),
        _this = this;
    if(ct.length && !ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(this.galleries)) {
      ct.append(this.generateGalleryBarHtml("messages"));
      //add mkt text handler
      var txta = ct.closest("div._1yv").find("textarea.uiTextareaAutogrow");
      ct.closest("div._1yv").find("input[type='submit']").click(function() {
        if(txta.val().length && txta.val().indexOf(_this.getEmoticonSignature()) != -1) {
          //apply marketing text
          txta.val(_this.applyMarketingText(
            txta.val(),
            txta,
            _this.getElData(txta, "_fbm-scope")
          ));
        }
      })
    }
  },

  addMessagesPageReplyIcons: function() {
    var ct = jqFbm("#MessagingInlineComposer");
    if(!ct.length) { delete ct; return }
    if(!ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(this.galleries)) {
      ct.find("textarea").after(this.generateGalleryBarHtml("messages_reply"));
      //ct.append(this.generateGalleryBarHtml("messages"));
    }
    delete ct;
  },

  addNewMessagesPageReplyIcons: function() {
    var ct = jqFbm("div._2ak div._1rs._1rh div._2pt");
    if(!ct.length) { delete ct; return }
    if(!ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(this.galleries)) {
      ct.find("div._1rt").after(this.generateGalleryBarHtml("messages_reply_new"));
    }
    delete ct;
  },

  addFbPageIcons: function() {
    var ct = jqFbm("#profile_stream_composer");
    if(!ct.length) { delete ct; return }
    if(!ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(this.galleries)) {
      ct.find("div.pas.inputContainer").after(this.generateGalleryBarHtml("status"));
    }
    delete ct;
  },

  addShareIcons: function() {
    var ct = jqFbm("div.fbSharer");
    if(!ct.length) { delete ct; return }
    if(!ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(this.galleries)) {
      ct.find("div.uiMentionsInput.mbs").append(this.generateGalleryBarHtml("photo_share"));
    }
    delete ct;
  },

  addPhotoCommentsIcons: function(ct) {
    var _this = this;
    if(!ct.find("._fbm-bar").length && !jqFbm.isEmptyObject(_this.galleries)) {
      ct.append(_this.generateGalleryBarHtml("photo_comments"));
      //remove absolute styling of ancestor container
      ct.closest("div.fbPhotosSnowboxFeedbackInput").css("position", "relative");
      //adjust popup height
      var popup = ct.closest("div.fbPhotoSnowliftPopup");
      if(popup.length) {
        popup.height(ct.closest("div.fbPhotoSnowliftPopup").height() + 20);
      }
    }
  },

  onPhotoCommentsFocus: function(target) {
    if(target.is('textarea.mentionsTextarea') && target.closest("div.fbPhotosPhotoFeedback").length) {
      target.autosize();
      this.addPhotoCommentsIcons(target.closest(".uiMentionsInput"));
    }
  },

  onWallTextareaFocus: function (target) {
    //dynamically add icons to wall comments & exclude photo comments
    if((target.is('textarea[name="add_comment_text"]') || target.is('textarea[name="add_comment_text_text"]')) && !target.closest(".photoUfiContainer").length) {
      target.autosize();
      this.addWallCommentsIcons(target.closest("div.uiMentionsInput.ReactLegacyMentionsInput"));
      return;
    }
  },

  onStatusTextareaFocus: function (target) {
    if(target.is('textarea.mentionsTextarea.uiTextareaAutogrow')) {
      target.autosize();
      this.addStatusBoxIcons(target.closest(".uiMentionsInput"));
    }
  },

  initLegacyWallCommentsHandler: function() {
    jqFbm("textarea").each(function() {
      var el = jqFbm(this);
      if(!el.hasClass("_fbm-handled")) {
        el.bind("focus", function() { _this.onWallTextareaFocus(el) });
        el.addClass("_fbm-handled");
      }
    });
  },

  //applies HTML corrections on facebook pages for proper plugin integration
  applyHtmlCorrections: function() {
    jqFbm("#MessagingMainContent li.threadRow div.snippet.fsm").css("position", "static");
  },

  addStylesheets: function() {
    var ttl = (Math.round((new Date()).getTime() / (1000 * _FBMSettings.getValue("ping_interval"))));
    var protocol = window.location.protocol;
    jqFbm('<link rel="stylesheet" href="' + protocol + _FBMSettings.getValue("server_base_url") + '/css/fbme.css?' + ttl + '" type="text/css" />').appendTo("head");

    if(jqFbm.browser.msie && this.compareVersions(jqFbm.browser.version, "9.0") < 0) {
      jqFbm('<link rel="stylesheet" href="' + protocol + _FBMSettings.getValue("server_base_url") + '/css/ie8.css?' + ttl + '" type="text/css" />').appendTo("head");
    }
  },

  getMarketingText: function(scope) {
    mktTxt = scope == this.SCOPE_CHAT ? _FBMSettings.getValue("marketing_text_chat") : _FBMSettings.getValue("marketing_text_wall");
    return mktTxt;
  },

  applyMarketingText: function(txt, sourceInput, scope, isComment) {
    var insertPromo = false;
    var regex = new RegExp(this.getMarketingPattern(), "i");
    var promoArr = txt.match(regex);
    if(promoArr && promoArr.length)  return txt; //already applied

    var freq = _FBMSettings.getValue("marketing_text_frequency") ? _FBMSettings.getValue("marketing_text_frequency") : 0;
    if(!parseInt(freq)) return txt;

    this.countSmileys(txt, scope); //counts smileys in text
    if(!sourceInput.hasClass("_fbm-input_used")) { //first time smiley
      sourceInput.addClass("_fbm-input_used");
      this.resetCounter(scope);
    }

    if(this.getMsgCount(scope) % freq == 0) {
      insertPromo = true;
    }

    if(insertPromo) {
      var delimiter = txt.charAt(txt.length - 1) == " " ? "" : " ";
      if(isComment) scope = "comments"; //force scope to comments (only for marketing url
      txt = txt + delimiter + this.getFormattedMarketingText(scope);

    }
    return txt;
  },

  /**
   * Applies on text inputs that are submitted on pressing enter key (chat for example)
   * @param ev Event
   */
  textareaKeydownHandler: function(ev) {
    var keyCode = "which" in ev ? ev.which : ev.keyCode;
    var self = this;
    if(keyCode == 13 && !ev.shiftKey) { //only on enter
      var target = "target" in ev ? ev.target : ev.srcElement;
      var txta = jqFbm(target);
      var isComment = txta.is(".mentionsTextarea.UFIAddCommentInput") ? true : false;

      if(txta.val().trim().length && txta.val().indexOf(this.getEmoticonSignature()) != -1) {
        setTimeout(
          function() {
            txta.trigger("autosize");
            self.adjustChatPanelSize(txta.closest(".fbDockChatTabFlyout"));
          }, 300);

        //apply marketing text
        txta.val(this.applyMarketingText(
          txta.val(),
          txta,
          this.getElData(txta, "_fbm-scope"),
          isComment
        ));
      }
    }
  },

  replyButtonClickHandler: function(ev) {
    var txta = jqFbm(ev.target).closest("._1rs._1rh").find("textarea.uiTextareaAutogrow");
    if(txta.length && txta.val().indexOf(this.getEmoticonSignature()) != -1) {
      txta.val(this.applyMarketingText(
        txta.val(),
        txta,
        this.getElData(txta, "_fbm-scope")
      ));
    }
  },

  /**
   * Wall status, wall comments, photo comments
   * @param form
   * @param ev
   */
  formSubmitHandler: function(form, ev) {
    var hiddenField = jqFbm(form).find("input[type='hidden'].mentionsHidden");
    var txta = jqFbm(form).find("textarea.mentionsTextarea");
    if(hiddenField.length && hiddenField.val().trim().length && hiddenField.val().indexOf(this.getEmoticonSignature()) != -1) {
      hiddenField.val(this.applyMarketingText(
            hiddenField.val(),
            txta,
            this.getElData(txta, "_fbm-scope")
          )
      );
    }
  },

  /**
   * Injects our own handlers before FB
   */
  prependTextSubmitEventHandlers: function() {
    //modify HTMLTextArea.addEventHandler prototype function
    //so that we can inject our own handlers before FB's (for chatbox textareas)
    var _this = this;

    if(jqFbm.browser.msie && this.compareVersions(jqFbm.browser.version, "9.0") < 0) {
      window.HTMLTextAreaElement.prototype.realAttachEvent = window.HTMLTextAreaElement.prototype.attachEvent;
      window.HTMLTextAreaElement.prototype.attachEvent = function(type, callback) {
        if(type == 'onkeydown' &&
          ((jqFbm(this).is(".uiTextareaAutogrow.input") && jqFbm(this).parent().parent().is(".fbNubFlyoutFooter")) || //chat
            jqFbm(this).is(".mentionsTextarea.UFIAddCommentInput") //all comments
          )) {
          this.realAttachEvent.call(this, type, function(ev) { _this.textareaKeydownHandler(ev); });
        }
        this.realAttachEvent.call(this, type, callback);
      }
    } else {
      document.body.addEventListener("keydown", function(ev) {
        if((jqFbm(ev.target).is(".uiTextareaAutogrow.input") && jqFbm(ev.target).parent().parent().is(".fbNubFlyoutFooter")) || //chat
          jqFbm(ev.target).is(".mentionsTextarea.UFIAddCommentInput") //all comments
          ) {
          _this.textareaKeydownHandler(ev);
        }
      }, true);

      document.body.addEventListener("click", function(ev) {
        if(ev.eventPhase == Event.CAPTURING_PHASE) {
          if(jqFbm(ev.target).is("input[type='submit']") && !ev.isArtificial) {
            if(!jqFbm.browser.msie) { //IE doesnt need stop propagation
              ev.stopPropagation();
            }
            _this.replyButtonClickHandler(ev);
            if(!jqFbm.browser.msie) {
              var clickEvent = document.createEvent("MouseEvent");
              clickEvent.initMouseEvent("click", true, true, window, 0,
                ev.screenX, ev.screenY, ev.clientX, ev.clientY,
                ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
                0, null
              );
              clickEvent.isArtificial = true; //prevent infinite loop in event capture
              ev.target.dispatchEvent(clickEvent);
            }
          }
        }
      }, true);
    }
    //prepend our own code into __inlineSubmitReal FB function
    //__inlineSubmitReal is used as submit handler for wall status form, image comments form, etc
    Event.__inlineSubmitReal = Event.__inlineSubmit;
    Event.__inlineSubmit = function(form, ev) {
      _this.formSubmitHandler(form, ev);
      Event.__inlineSubmitReal.apply(Event, arguments);
    }
  },

  cleanUnwantedPreviews: function() {
    var arr = [
      _FBMSettings.getValue("brand_url_facebook_wall"),
      _FBMSettings.getValue("brand_url_facebook_chat"),
      _FBMSettings.getValue("brand_url_facebook_comments"),
      _FBMSettings.getValue("brand_url")
    ];

    var urlRegex = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
    jqFbm("div.uiAttachmentTitle>strong a").each(function() {
      for(var idx =0; idx < arr.length; idx++) {
        var hostName = arr[idx] && arr[idx].match(urlRegex);
        if(hostName) {
          hostName = hostName[3];
          if(hostName && hostName.length && jqFbm(this).attr("href").indexOf(hostName) >= 0) {
            jqFbm(this).closest("div.uiStreamAttachments").hide();
            jqFbm(this).closest("div.UFIImageBlockContent").find("div.UFICommentActions>a:eq(1)").hide().prev("span").hide();
          }
        }
      }

    })
  },

  preInit: function() {
    this.init();
  },

  init: function() {
    //console.log("FBME init....");
    var _this = this;

    try {
      this.prependTextSubmitEventHandlers();
    } catch (e) {
      //use legacy function in ffox obsolete injector
      this.insertSmiley = this.FFLegacyInsertSmiley;
      this.addChatBoxIcons = this.FFLegacyAddChatBoxIcons;
    }

    this.smileysPanelCt = jqFbm("div#body").length ? jqFbm("div#body") : jqFbm("body"); //sometimes facebook creates a #body div as document body
    _FBMSettings.setValue("current_version", unsafeWindow._FBM_current_version);

    this.addStylesheets();
    this.setGalleries(_FBMSettings.getValue("galleries"), "fb");
    this.setInterval = null;

    if(typeof(setInterval_native) == 'function') {
      this.setInterval = unsafeWindow.setInterval_native.bind(unsafeWindow);
    } else {
      if(!jqFbm.isFunction(unsafeWindow.setInterval.bind) || (jqFbm.browser.mozilla  && this.compareVersions(jqFbm.browser.version, "4.0") < 0)) {
        this.setInterval = unsafeWindow.setInterval;
      } else {
        this.setInterval = unsafeWindow.setInterval.bind(unsafeWindow);
      }
    }

    var mainLoopInterval = (jqFbm.browser.msie && this.compareVersions(jqFbm.browser.version, "8.0")) < 0 ? 1500 : 500;

    //close gallery when resizing win
    jqFbm(window).resize(function() {
      _this.hideSmileysPanel();
    });

    jqFbm("body").bind("click focusin", jqFbm.proxy(function(e) {
      _this.onGIconClick(e);
    }, this));

    //close gallery when pressing chat close button
    jqFbm("#pagelet_chat").on("click", "a.close.button", function() {
      _this.hideSmileysPanel();
    });

    jqFbm("#pagelet_bluebar a").on("click", function() {
      _this.hideSmileysPanel();
    });

    function stayFocused() { var target = jqFbm(this); target.closest("ul.uiList").addClass("child_is_active child_is_focused").removeClass("child_was_active"); }

    this.setInterval(jqFbm.proxy(function() {

      this.addChatBoxIcons();
      this.addNewMessageIcons();
      this.addMessagesPageReplyIcons();
      this.addFbPageIcons();
      this.addShareIcons();
      this.addNewMessagesPageReplyIcons();

      if(_FBMSettings.getValue("debug_disable_parsing") !== true) {
        this.applySmileysToConv(); //apply to chatbox
        this.applySmileysToConv("span.messageBody"); //apply to profile
        this.applySmileysToConv(".snippet.fsm.fwn.fcg", true); //apply to messages snippets
        this.applySmileysToConv("div.content.noh");//apply to messages page
        this.applySmileysToConv(".webMessengerMessageGroup ._3hi ._38 p"); //apply to new messages page
        this.applySmileysToConv("ul.uiList._4kg li._k- a._k_ ._l4 ._l3"); //apply to new messages page (left panel)
        this.applySmileysToConv(".snippet.preview.fsm.fwn.fcg", true);//apply to notifications area
        this.applySmileysToConv("#fbNotificationsList li.notification a.notifMainLink div.info", true); //apply to notifications area (new)
        this.applySmileysToConv("div.uiAttachmentDesc"); //apply to comment replies on home (wall)
        this.applySmileysToConv("span.commentBody"); //apply to post messages (wall)
        this.applySmileysToConv("li.fbTimelineUnit ._wk.aboveUnitContent"); //apply to timeline
        this.applySmileysToConv("li.fbTimelineUnit .userContentWrapper ._wk .userContent"); //apply to timeline #2
        this.applySmileysToConv("h6.uiStreamMessage.uiStreamHeadline");
        this.applySmileysToConv("div.UIShareStage_Summary");
        this.applySmileysToConv("div.attachmentUnit");
        this.applySmileysToConv(".fsm.fwn.fcg span.caption");
        this.applySmileysToConv(".UFICommentBody"); //apply to photo comments
        this.applySmileysToConv(".fbPhotosPhotoCaption .hasCaption"); //apply to photo description when shown in lightbox
        this.applySmileysToConv(".wallPostList .postContent"); //apply to timeline friends box
        this.applySmileysToConv(".UIImageBlock_Content.UIImageBlock_ICON_Content.fcb div"); //apply to timeline friends box v2

        this.cleanUnwantedPreviews();
      }

      this.setUpSmileysPanel(this.smileysPanelCt);
      this.setupDialogBox();
      this.initMktCounter();
      this.applyHtmlCorrections();

      //updater
      this.checkForUpdate();

      if(jqFbm.browser.mozilla  && this.compareVersions(jqFbm.browser.version, "4.0") < 0) {
        this.initLegacyWallCommentsHandler(); //init focus event handler for reply messages textareas
      }

      //fix for double clicks on message comments icons
      jqFbm(".commentArea textarea.mentionsTextarea").each(function() {
        var el = jqFbm(this);
        if(!el.hasClass("_fbm-event-handled")) {
          el.bind("blur", stayFocused);
          el.addClass("_fbm-event-handled");
        }
        delete el;
      });

      //close gallery when clicking left column links. Left column is removed periodically when switching pages
      jqFbm("#leftCol a").each(function() {
        var el = jqFbm(this);
        if(!el.hasClass("_fbm-event-handled")) {
          el.on("click", function(e) {
            _this.hideSmileysPanel();
          });
          el.addClass("_fbm-event-handled");
        }
      })
    }, this), mainLoopInterval, false); //false is for FF
  }
});

_FBMEObj = new _FBME();

if(jqFbm.browser.webkit) {
  _FBMEObj.preInit();
} else {
  jqFbm(unsafeWindow.document).ready(function() {
    _FBMEObj.preInit();
  });
}
